#include "D3D9Engine.h"

#include "Helpers.h"


#define CASGE_STRING		"CasGEngine"


CD3D9Engine::CD3D9Engine(): _hwnd(NULL), _hdc(NULL), _winWidth(1024), _winHeight(768), _fullscr(false),
							_d3d9(NULL), _d3dDev(NULL), _title(CASGE_STRING), _engineInited(false),
							_input(NULL), _sound(NULL), _resFactory(NULL), _appActive(false), _isRunning(false)
{

}


CD3D9Engine::~CD3D9Engine()
{
	ReleaseEngine();
}


bool CD3D9Engine::CreateEngineApp(char* title, int w, int h, bool fullscr)
{
	_winWidth = w;
	_winHeight = h;
	_fullscr = fullscr;
	_title = title;
	_hInst = GetModuleHandle(0);
	_isSceneBegun = false;


	WNDCLASSEX wc;

	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(GetStockObject(0));
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	wc.hInstance = _hInst;
	wc.lpfnWndProc = (WNDPROC)StaticWndProc;
	wc.lpszClassName = CASGE_STRING;
	wc.lpszMenuName = NULL;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

	if(!RegisterClassEx(&wc))
	{
		LogEntry("Window class register fail!");
		return false;
	}

	int cx = (GetSystemMetrics(SM_CXSCREEN) / 2) - (_winWidth / 2);
	int cy = (GetSystemMetrics(SM_CYSCREEN) / 2) - (_winHeight / 2);

	RECT wndRect;
	SetRect(&wndRect, cx, cy, _winWidth, _winHeight);

	DWORD windowedFlags = WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX;
	DWORD fullscrFlags = WS_POPUP;

	AdjustWindowRect(&wndRect, ((_fullscr)? fullscrFlags : windowedFlags), FALSE);

	_hwnd = CreateWindowEx(0, 
							CASGE_STRING, 
							_title, 
							((_fullscr)? fullscrFlags : windowedFlags), 
							wndRect.left, 
							wndRect.top, 
							wndRect.right, 
							wndRect.bottom, 
							NULL, NULL, 
							_hInst, this);

	if(_hwnd == NULL)
	{
		LogEntry("HWND fail!");
		return false;
	}


	_d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
	if(!_d3d9)
	{
		LogEntry("Direct3DCreate9 fail!");
		return false;
	}

	D3DFORMAT format = D3DFMT_X8R8G8B8;//TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! TODO!!! 

	ZeroMemory(&_pp, sizeof(D3DPRESENT_PARAMETERS));

	_pp.BackBufferCount = 1;
	_pp.MultiSampleType = D3DMULTISAMPLE_NONE;
	_pp.MultiSampleQuality = 0;
	_pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	_pp.hDeviceWindow = _hwnd;
	_pp.Flags = 0;
	_pp.FullScreen_RefreshRateInHz = 0;
	_pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
	_pp.BackBufferFormat = format;
	_pp.EnableAutoDepthStencil = FALSE;


	if(_fullscr)
	{
		_pp.Windowed = FALSE;
		_pp.BackBufferWidth = wndRect.right;
		_pp.BackBufferHeight = wndRect.bottom;
	}
	else
	{
		_pp.Windowed = TRUE;
	}

	if(SUCCEEDED(_d3d9->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, format, format, !_fullscr)))
	{
		if(FAILED(_d3d9->CreateDevice(D3DADAPTER_DEFAULT,
			D3DDEVTYPE_HAL,
			_hwnd,
			D3DCREATE_SOFTWARE_VERTEXPROCESSING,
			&_pp,
			&_d3dDev)))
		{
			LogEntry("D3D CreateDevice fail!");
			SAFE_RELEASE(_d3d9);
			return false;
		}
	}
	else
	{
		LogEntry("D3D CheckDeviceType fail");
		SAFE_RELEASE(_d3d9);
		return false;
	}


	if(_fullscr)
	{
		ClipCursor(&wndRect);
	}


	if(!InitExternal())
	{
		LogEntry("Engine InitExternal fail!");
		return false;
	}

	LogEntry(Helper::StrConcat("Window & D3D9 creation OK (%ix%i F:%s, %s)!", this->_winWidth, this->_winHeight, (this->_fullscr)? "true" : "false", "X8R8G8B8"));
	
	return (_engineInited = true);
}


void CD3D9Engine::ReleaseEngine()
{
	ClipCursor(NULL);

	if(_engineInited)
	{
		SAFE_DELETE(_resFactory);
		SAFE_DELETE(_input);
		SAFE_DELETE(_sound);


		SAFE_RELEASE(_d3dDev);
		SAFE_RELEASE(_d3d9);


		UnregisterClass(CASGE_STRING, _hInst);

		_engineInited = false;
	}

	LogEntry("Window & D3D9 released!");
}


void CD3D9Engine::ToggleFullscreen()
{
	_fullscr = !_fullscr;

	if(_fullscr)
	{
		_pp.Windowed = FALSE;
		_pp.BackBufferWidth = _winWidth;
		_pp.BackBufferHeight = _winHeight;
	}
	else
	{
		_pp.Windowed = TRUE;
	}

	if(_d3dDev)
	{
		OnFreeResources();

		if(SUCCEEDED(_d3dDev->Reset(&_pp)))
		{
			OnInitResources();
		}
	}
}


bool CD3D9Engine::InitExternal()
{
	_resFactory = new CResourceFactory(this);
	
	_input = new CInputHID();

	if(_input)
		_input->CreateInputListener(_hwnd);

	_sound = new COpenAL();

	return true;
}

